package fr.vvins.core.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class DaoFactory implements ApplicationContextAware {
	
	private final static Logger log = LoggerFactory.getLogger(DaoFactory.class);
	
	private ApplicationContext applicationContext;
	
	/**	private Map<String, GenericDao<? extends Entity>> customDao = new HashMap<String, GenericDao<? extends Entity>>() ;
	
	public Map<String, Class<Entity>> classCache;
	
	private HibernateTemplate hibernateTemplate;

	public DaoFactory(){
	}
	
	public void init() {
	/*	classCache = Collections.synchronizedMap(new HashMap<String,Class<Entity>>());
		if(getHibernateTemplate() != null){
			Map<String, ClassMetadata> entities = getHibernateTemplate().getSessionFactory().getAllClassMetadata();
			if(entities != null){
				for(String entityName : entities.keySet()){
					ClassMetadata meta = entities.get(entityName);
					Class entityClass = meta.getMappedClass(EntityMode.POJO);
					if(!classCache.containsKey(entityClass.getSimpleName())){
						if(meta.getEntityName() != null){
							classCache.put(meta.getEntityName(), entityClass);	
						} else {
							classCache.put(entityClass.getSimpleName(), entityClass);
						}
					}
					if(entityClass.isAnnotationPresent(Dao.class)){
						createDao(entityClass);
					}
				}
			}
		}
	}
	
	public <T extends Entity> GenericDao<T> getDao(Class<T> entityClass){
		String entityName = entityClass.getSimpleName();
		javax.persistence.Entity e = (javax.persistence.Entity) entityClass.getAnnotation(javax.persistence.Entity.class);
		if(e.name() != null && !"".equals(e.name())){
			entityName = e.name();
		}
		return (GenericDao<T>) getCustomDao().get(entityName);
	}
	
	public GenericDao getDao(String entityName){
		return (GenericDao) getCustomDao().get(entityName);
	}
	
	@SuppressWarnings("unchecked")
	public <T extends Entity> void createDao(Class<T> entityClass){
		String entityName = entityClass.getSimpleName();
		javax.persistence.Entity entityAnnot = entityClass.getAnnotation(javax.persistence.Entity.class);
		if(entityAnnot.name() != null && !"".equals(entityAnnot.name())){
			entityName = entityAnnot.name();
		}
		
		Dao daoAnnot = entityClass.getAnnotation(Dao.class);
		Class daoClass = daoAnnot.daoClass();
		try {
			Constructor c = daoClass.getDeclaredConstructor(Class.class);
			GenericDao<T> dao = (GenericDao<T>) c.newInstance(entityClass);
			dao.setHibernateTemplate(getHibernateTemplate());
			if(GenericApplicationContext.class.isAssignableFrom(applicationContext.getClass())) {
				((GenericApplicationContext)applicationContext).getBeanFactory().registerSingleton(daoAnnot.name(), dao);
			} else if(XmlWebApplicationContext.class.isAssignableFrom(applicationContext.getClass())){
				((XmlWebApplicationContext)applicationContext).getBeanFactory().registerSingleton(daoAnnot.name(), dao);
			}
			getCustomDao().put(entityName, dao);
		} catch (NoSuchMethodException e) {
			log.error(e.getMessage(), e);
		} catch (SecurityException e) {
			log.error(e.getMessage(), e);
		} catch (InstantiationException e) {
			log.error(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			log.error(e.getMessage(), e);
		} catch (IllegalArgumentException e) {
			log.error(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			log.error(e.getMessage(), e);
		}
				
	}
	
	public Class<Entity> getEntityClass(String name) throws DataException {
		if(classCache.containsKey(name)){
			return classCache.get(name);
		} else {
			throw new DataException("Entity named " + name + " is unknown");
		}
		
	}

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	public Map<String, GenericDao<? extends Entity>> getCustomDao() {
		return customDao;
	}

	public void setCustomDao(Map<String, GenericDao<? extends Entity>> customDao) {
		this.customDao = customDao;
	}
*/
	@Override
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		applicationContext = context;
	}
	

}
